/*
 * Copyright © 2009 Gerald Isaac Schwarz
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package base;

import java.util.*;
import java.awt.Point;
import java.awt.Color;
import java.io.File;

public class CLI {
	public static final Character NEWLINE = Character.LINE_SEPARATOR;
	
	private Scanner sc = new Scanner(System.in);
	private ArrayList<String> exitValues = new ArrayList<String>();
	private Engine engine;
	private TurnListener turnListener = new TurnListener() {
		public void turnPerformed(TurnEvent te) {
			if (getEngine().getBoard().getPlayers().size() > 1) {
				printBoard();
				move();
			}
			else {
				printBoard();
				System.out.println(getEngine().getBoard().getPlayers().get(0).getName() + " has won!");
			}
		}

	};

	
	private Engine getEngine() {
		return this.engine;
	}
	
	private boolean isExitValue(String value) {
		for (String exitValue : exitValues) {
			if (value.equals(exitValue)) {
				return true;
			}
		}
		
		return false;
	}
	
	private boolean isLoadValue(String value) {
		if (value.equals("load")) {
			return true;
		}
		else {
			return false;
		}
	}

	private boolean isSaveValue(String value) {
		if (value.equals("save")) {
			return true;
		}
		else {
			return false;
		}
	}
	
	private int getInt() {
		String input = sc.nextLine();
		
		if (this.isExitValue(input)) {
			this.exit();
		}
		else if(this.isSaveValue(input)) {
			this.save();
		}
		else if(this.isLoadValue(input)) {
			this.load();
		}
		
		try {
			return Integer.parseInt(input);
		}
		catch (java.lang.NumberFormatException e) {
			System.out.println("Invalid input. Please try again:");
			return this.getInt();
		}
	}
	
	private String getString() {
		String input = sc.nextLine();
		
		if (this.isExitValue(input)) {
			this.exit();
		}
		else if(this.isSaveValue(input)) {
			this.save();
		}
		else if(this.isLoadValue(input)) {
			this.load();
		}
		
		return input;
	}
	
	private void load() {
		System.out.println("What file do you wish to load?");
		String input = sc.nextLine();
		System.out.println();
		
		File file = new File(input);
		
		if (file.exists()) {
			this.engine = (new GameLoader(file)).getEngine();
			
			this.getEngine().addTurnListener(this.turnListener);
			
			this.printBoard();
			this.move();
		}
		else {
			System.out.println("Specified file doesn't exist.");
			this.load();
		}
	}
	
	private void save() {
		System.out.println("Where do you want to save the game?");
		String output = sc.nextLine();
		System.out.println();
		
		File file = new File(output);
		
		if (!file.exists()) {
			new GameSaver(this.getEngine().getBoard(), file);
		}
		else {
			System.out.println("Specified file already exists.");
			this.save();
		}
	}
	
	private void exit() {
		System.out.println("Are you sure you wish to exit the game?");
		System.out.println("[Y] Yes");
		System.out.println("[N] No");
		
		String input = sc.nextLine();
		System.out.println();
		
		if (input.equalsIgnoreCase("Y")) {
			System.exit(0);
		}
		else if (!input.equalsIgnoreCase("N")) {
			System.out.println("Invalid input");
			this.exit();
		}
	}
	
	private void printBoard() {
		for (int y = 0; y < this.getEngine().getBoard().getSize().height; y++) {
			for (int x = 0; x < this.getEngine().getBoard().getSize().width; x++) {
				Point location = new Point(x, y);
				String label;
				
				if (!this.getEngine().getBoard().isEmpty(location)) {
					Piece piece = this.getEngine().getBoard().getPiece(location);
					
					label = this.getRepresentation(piece);
					
					if (piece.getOwner().getColor().equals(Color.BLACK)) {
						label = label.toUpperCase();
					}
					else {
						label = label.toLowerCase();
					}
				}
				else {
					label = "*";
				}
				
				System.out.print(label);
			}
			
			System.out.println();
		}
	}
	
	private String getRepresentation(Piece piece) {
		char ch = (char) (this.getEngine().getBoard().getCurrentState(piece).getLevel() + 64);
		return ch + "";
	}

	private void move() {
		Player player = this.getEngine().getBoard().getCurrentPlayer();
		Piece piece;
		Point origin = new Point();
		Point destination = new Point(-1, -1);
		
		System.out.println(player.getName() + ", please select a piece:");
		
		System.out.print("X: ");
		origin.x = this.getInt();
		
		System.out.print("Y: ");
		origin.y = this.getInt();
		
		
		if (!this.getEngine().getBoard().isEmpty(origin)) {
			piece = this.getEngine().getBoard().getPiece(origin);
			
			System.out.println("Please select a destination:");
			
			System.out.print("X: ");
			destination.x = this.getInt();
			
			System.out.print("Y: ");
			destination.y = this.getInt();
			
			if (!this.getEngine().move(piece, destination)) {
				System.out.println("Invalid input.");
				this.move();
			}
		}
		else {
			System.out.println("Invalid input.");
			this.move();
		}
	}
	
	private CLI() {
		
//		Set exit values:
		
		this.exitValues.add("exit");
		this.exitValues.add("quit");
		
//		Greeting:
		
		System.out.println("Hello, and welcom to stones CLI edition. To exit at any time, enter the word exit. To load a game, enter the word load. To save a game, enter the word save.");
		
		this.load();
	}
	
	public static void main(String[] args) {
		new CLI();
	}
}